package org.dei.perla.sys.utils;

import java.io.PrintStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;

public class TablePrettyPrinter {

	private static char V_SEPARATOR = '|';
	private static char O_SEPARATOR = '-';
	private static char JOINT = '+';
	private static char SPACE = ' ';
	private static TableFormatInfo formatInfo = new TableFormatInfo();
	
	public static void print(String header, ArrayList<String> list, int strForRow, PrintStream output) throws TablePrettyPrinterException{
		ArrayList<String[]> records = new ArrayList<String[]>();
		for (int i = 0; i < list.size(); i +=  strForRow) {
			String []array = new String[strForRow];
			for (int j = 0; j < array.length; j++) {
				array[j] = list.get(i + j);
			}
			records.add(array);
		}
		print(header, records, output);
	}
	
	public static void print(String header, ArrayList<String[]> list, PrintStream output) throws TablePrettyPrinterException{
		ArrayList<TableRecord> records = new ArrayList<TableRecord>(); 
		int lengths[] = new int[list.get(0).length];
		
		for (String[] element : list) {
			for (int i = 0; i < element.length; i++) {
				if(lengths[i] < element[i].length())
					lengths[i] = element[i].length();
			}
			TableRecord record = new TableRecord();
			record.setFields(element);
			records.add(record);
		}
		formatInfo.setFieldsLen(lengths);
		int tableRecordSize = formatInfo.getTableRecordSize();
		print(header, tableRecordSize, records, output);
	}

	
	private static void print(String header, int tableRecordSize, ArrayList<TableRecord> list, PrintStream output) throws TablePrettyPrinterException{
		int stdPos[] = {0, tableRecordSize -1};
		printHLine(tableRecordSize, stdPos, output);
		printHeaderString(header, tableRecordSize, output);
		printrecordAsHeader(list.get(0), tableRecordSize, output);		
		for (int i = 1; i < list.size() ; i++) {
			printRecord(list.get(i), output);
		}
		printHLine(tableRecordSize, stdPos, output);
	}

	private static void printrecordAsHeader(TableRecord tableRecord, int tableRecordSize, PrintStream output) throws TablePrettyPrinterException {
		int stdPos[] = new int[formatInfo.getFieldsLen().length + 1];
		for(int i = 1; i < stdPos.length; i++){
			stdPos[i] = stdPos[i-1] + formatInfo.getFieldsLen()[i - 1] + 1;
		}
		printHLine(tableRecordSize, stdPos, output);
		printRecord(tableRecord, output);
		printHLine(tableRecordSize, stdPos, output);
	}


	private static void printHeaderString(String header, int tableRecordSize, PrintStream output) {
		StringBuffer buffer = new StringBuffer();
		buffer.append(V_SEPARATOR);
		buffer.append(header);
		pad(buffer, tableRecordSize - 2 - header.length());
		buffer.append(V_SEPARATOR);
		output.println(buffer);
		
	}

	private static void printHLine(int size, int jPos[], PrintStream output) throws TablePrettyPrinterException{
		char array[] = new char[size];
		Arrays.fill(array, O_SEPARATOR);
		for (int i = 0; i < jPos.length; i++) {
			int pos = jPos[i];
			if(pos < size)
				array[pos] = JOINT;
			else
				throw new TablePrettyPrinterException();
		}
		output.println(array);
	}
	
	private static void pad(StringBuffer buffer, int padLen){
		if (padLen == 0)
			return;
		for(int i = 0; i < padLen ; i++){
			buffer.append(SPACE);
		}
	}
	
	private static void printRecord(TableRecord record, PrintStream output){
		ArrayList<String> fields = record.getFields();
		int fieldsLen[] = formatInfo.getFieldsLen();
		StringBuffer out = new StringBuffer();
		out.append(V_SEPARATOR);
		int i = 0;
		for (Iterator<String> iterator = fields.iterator(); iterator.hasNext();) {
			String string = (String) iterator.next();
			out.append(string);
			pad(out, fieldsLen[i++] - string.length());
			out.append(V_SEPARATOR);
		}
		output.println(out);
	}
}
